﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using com.yoozoo.gta.Extension;
using Gameplay.PVE.Survivor;
using OWL.Rendering.HRP;
using UnityEditor;
using UnityEngine;
using UnityEngine.Profiling;
using Yoozoo.HRP.Runtime;

public class MapFogGroup : MonoBehaviour
{
    public int textureWidth = 256;
    public int textureHeight = 256;
    public float edgeWidth = 0.5f;
    public List<Transform> edgePoints;
    public List<MapFogBlock> blocks = new List<MapFogBlock>();
    public SpriteRenderer renderer;
    private Material material;
    public Texture2D fillTexture;

    public Vector3 testPoint;

    public void TestPoint()
    {
        for (int k = 0; k < blocks.Count; k++)
        {
            var positions = new List<Vector3>();
            for (int i = 0; i < blocks[k].points.Count; i++)
            {
                positions.Add(blocks[k].points[i].position);
            }
            if (MapFogUtility.CheckPointIsInPolygon(positions, testPoint))
            {
                UnityEngine.Debug.LogError("在" + blocks[k].name + "内");
            }
        }
    }

    private List<GameObject> testCube = new List<GameObject>();
    private Transform testParent;
    
    public void GenerateImage()
    {
        Rebuild();
#if UNITY_EDITOR
        //先生成轮廓
        var outsides = new List<Vector3>();
        var left = float.MaxValue;
        var right = float.MinValue;
        var top = float.MinValue;
        var bottom = float.MaxValue;
        for (int i = 0; i < edgePoints.Count; i++)
        {
            left = Mathf.Min(left, edgePoints[i].position.x);
            right = Mathf.Max(right, edgePoints[i].position.x);
            top = Mathf.Max(top, edgePoints[i].position.z);
            bottom = Mathf.Min(bottom, edgePoints[i].position.z);
        }
        var max = Mathf.Max(right - left, top - bottom);
        var centerPoint = new Vector3(left + max / 2, transform.position.y, bottom + max / 2);
        centerPoint.y = 0;
        for (int i = 0; i < edgePoints.Count; i++)
        {
            var point = edgePoints[i].position - centerPoint;
            point.y = 0;
            outsides.Add(point);
        }
        RebuildBlocks(centerPoint);
        RemoveCube();
        testParent = new GameObject("TestParent").transform;
        var mapWidth = max;
        var mapHeight = max;
        var texture2d = new Texture2D(textureWidth,textureHeight);
        var textureFill = new Texture2D(textureWidth,textureHeight);
        var textureFillValid = false;
        for (int i = 0; i < textureWidth; i++)
        {
            for (int j = 0; j < textureHeight; j++)
            {
                var worldX = MapFogUtility.GetWorldXByTextureX(mapWidth,textureWidth,i);
                var worldY = MapFogUtility.GetWorldYByTextureY(mapHeight,textureHeight,j);
                var point = new Vector3(worldX, 0, worldY);
                var colorValue = 0;
                float r1 = 0;
                float g1 = 0;
                float b1 = 0;
                float a1 = 1;
                float r2 = 0;
                float g2 = 0;
                float b2 = 0;
                float a2 = 1;
                for (int k = 0; k < blocks.Count; k++)
                {
                    if (!blocks[k].gameObject.activeInHierarchy)
                    {
                        continue;
                    }
                    var positions = new List<Vector3>();
                    for (int m = 0; m < blocks[k].points.Count; m++)
                    {
                        var pos = blocks[k].points[m].position - centerPoint;
                        pos.y = 0;
                        positions.Add(pos);
                    }

                    Vector3 p1 = Vector3.zero;
                    Vector3 p2 = Vector3.zero;
                    var distance = MapFogUtility.GetDistanceToPolygonEdge(positions, point,ref p1,ref p2);
                    if (distance == 0)
                    {
                        
                    }
                    else
                    {
                        p1 = p1 + centerPoint;
                        p2 = p2 + centerPoint;
                        distance = Mathf.Min(distance, edgeWidth);
                        var percent = distance / edgeWidth;
                        /*var cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
                        cube.name = "TestCube " + distance + " " + p1 + " " + p2;
                        cube.transform.parent = testParent;
                        cube.transform.position = point + centerPoint + new Vector3(0,percent / 2,0);
                        cube.transform.localScale = new Vector3(0.05f,percent,0.05f);
                        testCube.Add(cube);*/
                        var id = blocks[k].id;
                        if (blocks[k].renderType == EFogRenderType.Hole)
                        {
                            if (id == 1)
                            {
                                r1 = Mathf.Max(r1,0 + percent);
                            }
                            if (id == 2)
                            {
                                g1 = Mathf.Max(g1,0 + percent);
                            }
                            if (id == 3)
                            {
                                b1 = Mathf.Max(b1,0 + percent);
                            }
                            if (id == 4)
                            {
                                a1 = Mathf.Min(a1,1 - percent);
                            }
                        }
                        else
                        {
                            textureFillValid = true;
                            if (id == 5)
                            {
                                r2 = Mathf.Max(r1,0 + percent);
                            }
                            if (id == 6)
                            {
                                g2 = Mathf.Max(g1,0 + percent);
                            }
                            if (id == 7)
                            {
                                b2 = Mathf.Max(b1,0 + percent);
                            }
                            if (id == 8)
                            {
                                a2 = Mathf.Min(a1,1 - percent);
                            }
                        }
                        
                    }
                }
                var color = new Color(r1,g1,b1,a1);
                texture2d.SetPixel(i,j,color);
                color = new Color(r2,g2,b2,a2);
                textureFill.SetPixel(i,j,color);
            }
        }
        texture2d.Apply();
        textureFill.Apply();
        byte[] dataBytes = texture2d.EncodeToPNG();
        var p = "/ResourcesAssets/Pve/Survivor/Textures/Map/" + name + ".png";
        string path = Application.dataPath + p;
        FileStream fileSteam = File.Open(path, FileMode.OpenOrCreate);
        fileSteam.Write(dataBytes, 0, dataBytes.Length);
        fileSteam.Close();

        var pp = "/ResourcesAssets/Pve/Survivor/Textures/Map/" + name + "_fill.png";
        if (textureFillValid)
        {
            dataBytes = textureFill.EncodeToPNG();
            path = Application.dataPath + pp;
            fileSteam = File.Open(path, FileMode.OpenOrCreate);
            fileSteam.Write(dataBytes, 0, dataBytes.Length);
            fileSteam.Close();
        }
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
        UnityEngine.Debug.LogError("保存成功"+path);
        if (textureFillValid)
        {
            var texture = AssetDatabase.LoadAssetAtPath<Texture2D>("Assets" + pp);
            this.fillTexture = texture;
        }
        renderer.transform.localScale = new Vector3(mapHeight / (textureWidth / 100f), mapWidth / (textureHeight / 100f), 1);
        renderer.transform.position = new Vector3(centerPoint.x, renderer.transform.position.y,centerPoint.z);
        var sprite = AssetDatabase.LoadAssetAtPath<Sprite>("Assets" + p);
        renderer.sprite = sprite;
        renderer.sharedMaterial.SetTexture("_FillTex",  fillTexture);
        renderer.sharedMaterial.SetFloat("_FillTexWeight", fillTexture == null ? 0 : 1);
        /*for (int i = 0; i < blocks.Count; i++)
        {
            if (blocks[i].renderType == EFogRenderType.Hole)
            {
                continue;
            }
            outsides.Clear();
            left = float.MaxValue;
            right = float.MinValue;
            top = float.MinValue;
            bottom = float.MaxValue;
            for (int j = 0; j < blocks[i].points.Count; j++)
            {
                left = Mathf.Min(left, blocks[i].points[j].position.x);
                right = Mathf.Max(right, blocks[i].points[j].position.x);
                top = Mathf.Max(top, blocks[i].points[j].position.z);
                bottom = Mathf.Min(bottom, blocks[i].points[j].position.z);
            }
            centerPoint = new Vector3(left + max / 2, transform.position.y, bottom + max / 2);
            centerPoint.y = 0;
            for (int j = 0; j < blocks[i].points.Count; j++)
            {
                var point = blocks[i].points[j].position - centerPoint;
                point.y = 0;
                outsides.Add(point);
            }
            texture2d = new Texture2D(fillTextureWidth,fillTextureHeight);
            for (int i = 0; i < fillTextureWidth; i++)
            {
                for (int j = 0; j < fillTextureHeight; j++)
                {
                    var worldX = MapFogUtility.GetWorldXByTextureX(mapWidth,fillTextureWidth,i);
                    var worldY = MapFogUtility.GetWorldYByTextureY(mapHeight,fillTextureHeight,j);
                    var point = new Vector3(worldX, 0, worldY);
                    for (int k = 0; k < blocks.Count; k++)
                    {
                        if (blocks[k].renderType != EFogRenderType.Hole)
                        {
                            continue;
                        }

                        if (!blocks[k].gameObject.activeInHierarchy)
                        {
                            continue;
                        }

                        var positions = new List<Vector3>();
                        for (int m = 0; m < blocks[k].points.Count; m++)
                        {
                            var pos = blocks[k].points[m].position - centerPoint;
                            pos.y = 0;
                            positions.Add(pos);
                        }

                        Vector3 p1 = Vector3.zero;
                        Vector3 p2 = Vector3.zero;
                        var distance = MapFogUtility.GetDistanceToPolygonEdge(positions, point, ref p1, ref p2);
                        if (distance == 0)
                        {

                        }
                    }
                }
            }
        }*/
#endif
    }

    public void Init(int fogMask)
    {
        material = renderer.material;
        this.fogMask = fogMask;
        material.SetInt("_FogMask",fogMask);
        if (fillTexture)
        {
            material.SetTexture("_FillTex",fillTexture);
            material.SetFloat("_FillTexWeight",1);
        }
        else
        {
            material.SetTexture("_FillTex",null);
            material.SetFloat("_FillTexWeight",0);
        }
    }

    private int fogMask = 0;
    
    public void UnlockFog(int value)
    {
        #if UNITY_EDITOR
        if (material == null)
        {
            material = renderer.sharedMaterial;
        }
        #endif
        this.fogMask = value;
        //处理一下，低5位保留，高4位取反
        var lowerMask = (1 << 5) - 1;
        var lower = fogMask & lowerMask;
        value = ~value;
        value = value >> 5;
        value = value << 5;
        value = value | lower;
        material.SetInt("_FogMask",value);
    }

    public bool IsFogLock(int value)
    {
        return (fogMask & (1 << value)) == 0;
    }
    
    private void Rebuild()
    {
        edgePoints.Clear();
        var child = transform.Find("Edge");
        if (child == null)
        {
            return;
        }

        for (int i = 0; i < child.childCount; i++)
        {
            var point = child.GetChild(i);
            edgePoints.Add(point);
        }
    }

    private void RebuildBlocks(Vector3 center)
    {
        blocks.Clear();
        var blocksComponent = GetComponentsInChildren<MapFogBlock>();
        var index = 1;
        var idMap = new HashSet<int>();
        for (int i = 0; i < blocksComponent.Length; i++)
        {
            var name = blocksComponent[i].name.Split('_');
            if (name.Length == 2)
            {
                blocksComponent[i].name = name[0];
            }

            if (idMap.Contains(blocksComponent[i].id))
            {
                var offset = blocksComponent[i].renderType == EFogRenderType.Hole ? 0 : 4;
                for (int j = 1 + offset; j <= 4 + offset; j++)
                {
                    if (!idMap.Contains(j))
                    {
                        blocksComponent[i].id = j;
                        break;
                    }
                }
            }
            idMap.Add(blocksComponent[i].id);
            blocksComponent[i].name = blocksComponent[i].name + "_" + blocksComponent[i].id;
            blocksComponent[i].Rebuild(center);
            blocks.Add(blocksComponent[i]);
        }
    }

    private void OnDrawGizmos()
    {
        var blocksComponent = GetComponentsInChildren<MapFogBlock>();
        for (int i = 0; i < blocksComponent.Length; i++)
        {
            blocksComponent[i].DrawGizmos();
        }
    }

    private void OnDestroy()
    {
#if UNITY_EDITOR
        RemoveCube();
#endif
    }

    private void RemoveCube()
    {
        if (testParent != null)
        {
            GameObject.DestroyImmediate(testParent.gameObject);
        }
        testCube.Clear();
    }
}